﻿using System;
using System.Collections.Generic;
using Framework.Core.BootStrapper.WindowsService;
using Framework.Core.CommandLine;
using Framework.Core.Io;
using Framework.Core.Process;
using Rhino.Mocks;
using Xunit;

namespace Framework.Tests.Core.BootStrapper
{
    class WindowsServicePluginSample : WindowsServicePlugin<WindowsServiceArgs>
    {
        private readonly IWindowsService<WindowsServiceArgs> mock;

        public WindowsServicePluginSample()
        {
        }

        public WindowsServicePluginSample(IWindowsService<WindowsServiceArgs> mock, IProcessController processController, IServiceBaseAdapter serviceBaseAdapter, IConsoleAdapter consoleAdapter, ICommandLineParser commandLineParser)
            : base(processController, serviceBaseAdapter, consoleAdapter, commandLineParser)
        {
            this.mock = mock;
        }

        public override void Start(WindowsServiceArgs args)
        {
            mock.Start(args);
        }

        public override void Stop()
        {
            mock.Stop();
        }
    }

    public class WindowsServiceBootStrapperTest
    {
        private readonly WindowsServicePlugin<WindowsServiceArgs> windowsServicePlugin;
        private readonly MockRepository mockRepository = new MockRepository();
        private readonly IProcessController processController;
        private readonly IServiceBaseAdapter serviceBaseAdapterMock;
        private readonly IConsoleAdapter consoleAdapterMock;
        private readonly ICommandLineParser commandLineParserMock;
        private readonly IWindowsService<WindowsServiceArgs> windowsServiceMock;

        public WindowsServiceBootStrapperTest()
        {
            processController = mockRepository.StrictMock<IProcessController>();
            serviceBaseAdapterMock = mockRepository.StrictMock<IServiceBaseAdapter>();
            consoleAdapterMock = mockRepository.StrictMock<IConsoleAdapter>();
            windowsServiceMock = mockRepository.StrictMock<IWindowsService<WindowsServiceArgs>>();
            commandLineParserMock = mockRepository.StrictMock<ICommandLineParser>();
            windowsServicePlugin = new WindowsServicePluginSample(windowsServiceMock, processController, serviceBaseAdapterMock, consoleAdapterMock, commandLineParserMock);
        }

        [Fact]
        public void Should_return_negative_code_when_args_install_mode_is_not_valid()
        {
            var windowsServiceArgs = new WindowsServiceArgs { IsInstallMode = true, Args = "" };

            var serviceArgs = new[] { "/p:pouet" };
            commandLineParserMock
                .Expect(x => x.Parse<WindowsServiceArgs>(serviceArgs))
                .Return(windowsServiceArgs);

            commandLineParserMock
                .Expect(x => x.Parse<WindowsServiceArgs>(new[] { windowsServiceArgs.Args }))
                .Throw(new ArgumentException());

            mockRepository.ReplayAll();
            Assert.Equal(-1, windowsServicePlugin.Execute(serviceArgs));
            mockRepository.VerifyAll();

        }

        [Fact]
        public void Should_install_windows_service()
        {
            const string argsToInstall = "/pouet";
            var windowsServiceArgs = new WindowsServiceArgs { IsInstallMode = true, Args = argsToInstall };
            var serviceArgs = new[] { string.Format("/i /a:{0}", argsToInstall) };
            processController.Expect(x => x.Install(windowsServiceArgs));
            commandLineParserMock.Expect(x => x.Parse<WindowsServiceArgs>(serviceArgs)).Return(windowsServiceArgs);
            commandLineParserMock.Expect(x => x.Parse<WindowsServiceArgs>(Arg<string[]>.List.ContainsAll(new List<string> { argsToInstall }))).Return(new WindowsServiceArgs());
            mockRepository.ReplayAll();
            Assert.Equal(0, windowsServicePlugin.Execute(serviceArgs));
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_uninstall_windows_service()
        {
            var windowsServiceArgs = new WindowsServiceArgs { IsUninstallMode = true };
            var serviceArgs = new[] { "/u" };
            commandLineParserMock.Expect(x => x.Parse<WindowsServiceArgs>(serviceArgs)).Return(windowsServiceArgs);
            processController.Expect(x => x.Uninstall(windowsServiceArgs));
            mockRepository.ReplayAll();
            Assert.Equal(0, windowsServicePlugin.Execute(serviceArgs));
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_run_in_console_windows_service()
        {
            var windowsServiceArgs = new WindowsServiceArgs { IsConsoleMode = true };
            var serviceArgs = new[] { "/C" };

            commandLineParserMock.Expect(x => x.Parse<WindowsServiceArgs>(serviceArgs)).Return(windowsServiceArgs).Repeat.Times(2);
            windowsServiceMock.Expect(x => x.Start(windowsServiceArgs));
            consoleAdapterMock.Expect(x => x.Read()).Return(1);
            windowsServiceMock.Expect(x => x.Stop());

            mockRepository.ReplayAll();
            Assert.Equal(0, windowsServicePlugin.Execute(serviceArgs));
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_run_windows_service()
        {
            var windowsServiceArgs = new WindowsServiceArgs { IsConsoleMode = false };

            serviceBaseAdapterMock.Expect(x => x.Run(windowsServicePlugin, windowsServiceArgs));
            mockRepository.ReplayAll();
            Assert.Equal(0, windowsServicePlugin.Execute(windowsServiceArgs));
            mockRepository.VerifyAll();
        }

        [Fact]
        public void Should_have_constructor_without_parameter()
        {
            Assert.NotNull(new WindowsServicePluginSample());
        }
    }
}
